package com.yonyou.crm.common.http.client;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import net.sf.json.JSONObject;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethodBase;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.DeleteMethod;
import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.lang.StringUtils;

import com.yonyou.crm.common.exception.CrmMessageException;

public class CrmHttpClient {

	private final static String ContentType = "application/json";
	private final static String EncodeType = "UTF-8";
	private final static String Get = "get";
	private final static String Delete = "delete";
	private final static String Post = "post";
	private final static String Put = "put";
	
	
	/**
	 * Get请求
	 * @param url 请求url，附带在url中
	 * @return
	 * @throws CrmMessageException
	 */
	public static CrmResponse get(String url) throws CrmMessageException {	
		return request(getMethod(Get, url));
	}
	
	/**
	 * Get请求
	 * @param url 请求url
	 * @param paraMap 参数
	 * @return
	 * @throws CrmMessageException
	 */
	public static CrmResponse get(String url, Map<String, String> paraMap) throws CrmMessageException {	
		return request(getMethod(Get, appendUrl(url, paraMap)));
	}
	
	/**
	 * Get请求
	 * @param url 请求url
	 * @param paraMap 参数
	 * @param headerMap 请求头信息
	 * @return
	 * @throws CrmMessageException
	 */
	public static CrmResponse get(String url, Map<String, String> paraMap, Map<String, String> headerMap) throws CrmMessageException {	
		
		GetMethod method = (GetMethod) getMethod(Get, appendUrl(url, paraMap));
		
		setRequestHeader(method, headerMap);
		
		return request(method);
	}
	
	/**
	 * Delete请求
	 * @param url 请求url
	 * @param para 参数
	 * @return
	 * @throws CrmMessageException
	 */
	public static CrmResponse delete(String url, Map<String, String> para) throws CrmMessageException {

		DeleteMethod method = (DeleteMethod) getMethod(Delete, url);
		
        List<NameValuePair> data = new ArrayList<NameValuePair>();
        if(para != null && para.size() > 0){

            for (Map.Entry<String, String> entry : para.entrySet()) {
            	data.add(new NameValuePair(entry.getKey(), entry.getValue()));
            }

            method.setQueryString(data.toArray(new NameValuePair[0]));
        } 

		return request(method);
	}
	
	/**
	 * Post请求
	 * @param url 请求url
	 * @param paramObj 参数
	 * @return
	 * @throws CrmMessageException
	 */
	public static CrmResponse post(String url, JSONObject paramObj) throws CrmMessageException {
		return entityEnclosing((EntityEnclosingMethod) getMethod(Post, url), paramObj, ContentType, EncodeType);
	}
	
	/**
	 * Post请求
	 * @param url 请求url
	 * @param paramObj 参数
	 * @param headerMap 请求头信息
	 * @return
	 * @throws CrmMessageException
	 */
	public static CrmResponse post(String url, JSONObject paramObj, Map<String, String> headerMap) throws CrmMessageException {
		
		PostMethod method = (PostMethod) getMethod(Post, url);
		
		setRequestHeader(method, headerMap);
		
		return entityEnclosing(method, paramObj, ContentType, EncodeType);
	}
	
	/**
	 * Put请求
	 * @param url 请求url
	 * @param paramObj 参数
	 * @return
	 * @throws CrmMessageException
	 */
	public static CrmResponse put(String url, JSONObject paramObj) throws CrmMessageException {
		return entityEnclosing((EntityEnclosingMethod) getMethod(Put, url), paramObj, ContentType, EncodeType);
	}
	
	/**
	 * Put请求
	 * @param url 请求url
	 * @param paramObj 参数
	 * @param headerMap 请求头信息
	 * @return
	 * @throws CrmMessageException
	 */
	public static CrmResponse put(String url, JSONObject paramObj, Map<String, String> headerMap) throws CrmMessageException {
		
		PutMethod method = (PutMethod) getMethod(Put, url);
		
		setRequestHeader(method, headerMap);
		
		return entityEnclosing(method, paramObj, ContentType, EncodeType);
	}

	private static CrmResponse entityEnclosing(EntityEnclosingMethod method, JSONObject paramObj, String contentType, String encodeType) throws CrmMessageException {
		
		try {
			method.setRequestEntity(new StringRequestEntity(paramObj==null ? "" : paramObj.toString(), contentType, encodeType));
		} catch (UnsupportedEncodingException e) {
			throw new CrmMessageException("转换请求实体异常");
		}

		return request(method);
	}
	
	/**
	 * 发送请求
	 * @param method 请求方法
	 * @return
	 * @throws CrmMessageException
	 */
	private static CrmResponse request(HttpMethodBase method) throws CrmMessageException {
		
		CrmResponse response = new CrmResponse();
		HttpClient httpClient = new HttpClient();	
		
		try {

			httpClient.executeMethod(method);

			response.setCode(method.getStatusCode());
			response.setData(method.getResponseBodyAsString());

		} catch (HttpException e) {
			throw new CrmMessageException("请求远程接口异常");
		} catch (IOException e) {
			throw new CrmMessageException("文件转换异常");
		} catch (Exception e) {
			throw new CrmMessageException("未知的异常");
		} 
		finally {
			method.releaseConnection();
		}
		return response;
	}
	
	/**
	 * 获取请求方法
	 * @param type 类型
	 * @param url 请求url
	 * @return
	 * @throws CrmMessageException
	 */
	private static HttpMethodBase getMethod(String type, String url) throws CrmMessageException {
		
		if (StringUtils.isBlank(url)) {
			throw new CrmMessageException("请求URL不能为空");
		}
		
		HttpMethodBase method = null;
		switch (type) {
		case Get:
			method = new GetMethod(url);
			break;
		case Delete:
			method = new DeleteMethod(url);
			break;
		case Post:
			method = new PostMethod(url);
			break;
		case Put:
			method = new PutMethod(url);
			break;

		default:
			break;
		}
		return method;
	}
	
	/**
	 * 设置请求头
	 * @param method 要设置的请求
	 * @param headerMap 请求头信息
	 */
	private static void setRequestHeader(HttpMethodBase method, Map<String, String> headerMap) {
		
		if (headerMap != null && headerMap.size() > 0) {
			
			for (Map.Entry<String, String> entry : headerMap.entrySet()) {
				method.setRequestHeader(entry.getKey(), entry.getValue());
			}
		}
	}
	
	/**
	 * 拼接url
	 * @param url 初始url
	 * @param paraMap 参数
	 * @return
	 * @throws CrmMessageException
	 */
	private static String appendUrl(String url, Map<String, String> paraMap) throws CrmMessageException {
		
		if (StringUtils.isNotBlank(url)) {
			
			if (paraMap != null && paraMap.size() > 0) {
				
				StringBuffer uBuffer = new StringBuffer(url);
				if (uBuffer.indexOf("?", url.length()) < 0) {
					uBuffer.append("?");
				}

				for (Map.Entry<String, String> entry : paraMap.entrySet()) {
					try {
						uBuffer.append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue(), "UTF-8")).append("&");
					} catch (UnsupportedEncodingException e) {
						throw new CrmMessageException("url转换编码失败");
					}
				}
				
				uBuffer.delete(uBuffer.length() - 1, uBuffer.length());
				
				return uBuffer.toString();
			}
		}

		return url;
	}

}
